
 <!DOCTYPE HTML>
<html >
<head>
  <meta charset="UTF-8">
  
    <title>周报 | B3434lockchain</title>
    <meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
    
    <meta name="author" content="b3434lockchain">
    

    
    <meta name="description" content="1.手动启动first-network的准备工作1.1.生成组织结构及身份证书首先查看一下组织关系的模板 $ sudo ../bin/cryptogen showtemplate 组织结构： OrdererOrgs:   - Name: Orderer    order节点名称     Domain: example.com    域名     Specs:       - Hostname: o">
<meta name="keywords" content="周报,卢家豪">
<meta property="og:type" content="article">
<meta property="og:title" content="周报">
<meta property="og:url" content="http://b3434lockchain.gitee.io/2018/11/05/lujiahao/lujiahao4/index.html">
<meta property="og:site_name" content="B3434lockchain">
<meta property="og:description" content="1.手动启动first-network的准备工作1.1.生成组织结构及身份证书首先查看一下组织关系的模板 $ sudo ../bin/cryptogen showtemplate 组织结构： OrdererOrgs:   - Name: Orderer    order节点名称     Domain: example.com    域名     Specs:       - Hostname: o">
<meta property="og:locale" content="default">
<meta property="og:updated_time" content="2018-11-05T08:39:10.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="周报">
<meta name="twitter:description" content="1.手动启动first-network的准备工作1.1.生成组织结构及身份证书首先查看一下组织关系的模板 $ sudo ../bin/cryptogen showtemplate 组织结构： OrdererOrgs:   - Name: Orderer    order节点名称     Domain: example.com    域名     Specs:       - Hostname: o">

    
    <link rel="alternative" href="/atom.xml" title="B3434lockchain" type="application/atom+xml">
    
    
    <link rel="icon" href="/img/favicon.ico">
    
    
    <link rel="apple-touch-icon" href="/img/jacman.jpg">
    <link rel="apple-touch-icon-precomposed" href="/img/jacman.jpg">
    
    <link rel="stylesheet" href="/css/style.css">
</head>

  <body>
    <header>
      
<div>
		
			<div id="imglogo">
				<a href="/"><img src="/img/logo.png" alt="B3434lockchain" title="B3434lockchain"/></a>
			</div>
			
			<div id="textlogo">
				<h1 class="site-name"><a href="/" title="B3434lockchain">B3434lockchain</a></h1>
				<h2 class="blog-motto"></h2>
			</div>
			<div class="navbar"><a class="navbutton navmobile" href="#" title="Menu">
			</a></div>
			<nav class="animated">
				<ul>
					<ul>
					 
						<li><a href="/">Home</a></li>
					
						<li><a href="/archives">Archives</a></li>
					
						<li><a href="/about">About</a></li>
					
					<li>
 					
						<form class="search" action="https://www.baidu.com" target="_blank">
							<label>Search</label>
						<input name="s" type="hidden" value=  ><input type="text" name="q" size="30" placeholder="Search"><br>
						</form>
					
					</li>
				</ul>
			</nav>			
</div>
    </header>
    <div id="container">
      <div id="main" class="post" itemscope itemprop="blogPost">
  
	<article itemprop="articleBody"> 
		<header class="article-info clearfix">
  <h1 itemprop="name">
    
      <a href="/2018/11/05/lujiahao/lujiahao4/" title="周报" itemprop="url">周报</a>
  </h1>
  <p class="article-author">By
       
		<a href="/about" title="b3434lockchain" target="_blank" itemprop="author">b3434lockchain</a>
		
  <p class="article-time">
    <time datetime="2018-11-05T09:00:00.000Z" itemprop="datePublished"> Published 2018-11-05</time>
    
  </p>
</header>
	<div class="article-content">
		
		<div id="toc" class="toc-article">
			<strong class="toc-title">Contents</strong>
		
			<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1-手动启动first-network的准备工作"><span class="toc-number">1.</span> <span class="toc-text">1.手动启动first-network的准备工作</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-1-生成组织结构及身份证书"><span class="toc-number">1.1.</span> <span class="toc-text">1.1.生成组织结构及身份证书</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-2-创建Orderer的初始区块并启动Orderer服务"><span class="toc-number">1.2.</span> <span class="toc-text">1.2.创建Orderer的初始区块并启动Orderer服务</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-3-生成应用通道配置交易文件"><span class="toc-number">1.3.</span> <span class="toc-text">1.3.生成应用通道配置交易文件</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-4-生成锚节点更新配置文件"><span class="toc-number">1.4.</span> <span class="toc-text">1.4.生成锚节点更新配置文件</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2-启动网络"><span class="toc-number">2.</span> <span class="toc-text">2.启动网络</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#2-1-启动Docker容器"><span class="toc-number">2.1.</span> <span class="toc-text">2.1.启动Docker容器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-2-进入容器中"><span class="toc-number">2.2.</span> <span class="toc-text">2.2.进入容器中</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-3-创建应用通道"><span class="toc-number">2.3.</span> <span class="toc-text">2.3.创建应用通道</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-4-将对应节点加入到应用通道"><span class="toc-number">2.4.</span> <span class="toc-text">2.4.将对应节点加入到应用通道</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-5-更新锚节点"><span class="toc-number">2.5.</span> <span class="toc-text">2.5.更新锚节点</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-测试自己编写的链码"><span class="toc-number">3.</span> <span class="toc-text">3.测试自己编写的链码</span></a></li></ol>
		
		</div>
		
		<h1 id="1-手动启动first-network的准备工作"><a href="#1-手动启动first-network的准备工作" class="headerlink" title="1.手动启动first-network的准备工作"></a>1.手动启动first-network的准备工作</h1><h2 id="1-1-生成组织结构及身份证书"><a href="#1-1-生成组织结构及身份证书" class="headerlink" title="1.1.生成组织结构及身份证书"></a>1.1.生成组织结构及身份证书</h2><p>首先查看一下组织关系的模板</p>
<p><code>$ sudo ../bin/cryptogen showtemplate</code></p>
<pre><code>组织结构：
OrdererOrgs:
  - Name: Orderer    order节点名称
    Domain: example.com    域名
    Specs:
      - Hostname: orderer 主机名称
            主机名称：域名


组织结构：
PeerOrgs:
  - Name: Org1     peer节点
    Domain: org1.example.com     域名
    EnableNodeOUs: true
    Template:   # 指定Org1组织下的peer节点数量
      Count: 1 
    Users:  # 指定Org1组织下的管理员用户数量
      Count: 2
      Admin(默认)
      User1
      User2

节点名称：peer0.org1.example.com

  - Name: Org2   组织二
    Domain: org2.example.com
    EnableNodeOUs: true
    Template:   # 指定Org2组织下的peer节点数量
      Count: 1
    Users:
      Count: 1

peer0.org2.example.com
</code></pre><p>进入到first-network目录，使用指定的配置文件为网络生成制定拓扑结构的组织关系和身份证书</p>
<pre><code>$ cd first-network/

$ sudo ../bin/cryptogen generate --config=./crypto-config.yaml
</code></pre><p>通过以上命令会产生如下的输出：</p>
<pre><code>org1.example.com
org2.example.com
</code></pre><p>证书和密钥（即MSP材料）将被输出到目录 first-network/crypto-config 的目录中。其中 ordererOrganizations 子目录下包括构成 Orderer 组织(1个Orderer节点)的身份信息。而 peerOrganizations子目录下为所有的Peer节点组织(2个组织, 4个节点)的相关身份信息. 其中最关键的是MSP目录, 代表了实体的身份信息。</p>
<p>crypto-config文件目录结构如下:</p>
<pre><code>crypto-config
├── ordererOrganizations
│   └── example.com
│       ├── ca     当前orderer的私钥文件
│       │   ├── ca.example.com-cert.pem     ca根证书
│       │   └── df69b6d2aea8038270c5340d358bfe34eee039a8e16d4a849e67ec27a8ed53bd_sk    私钥
│       ├── msp     成员服务提供者
│       │   ├── admincerts   管理员
│       │   │   └── Admin@example.com-cert.pem
│       │   ├── cacerts      ca证书
│       │   │   └── ca.example.com-cert.pem同根证书
│       │   └── tlscacerts      tls的证书
│       │       └── tlsca.example.com-cert.pem
│       ├── orderers
│       │   └── orderer.example.com     当前orderer相应的组织（有的业务场景会需要多个order的时候）
│       │       ├── msp
│       │       │   ├── admincerts    管理员证书
│       │       │   ├── cacerts       ca证书
│       │       │   ├── keystore      sk私钥
│       │       │   ├── signcerts    orderer证书
│       │       │   └── tlscacerts    tls证书
│       │       └── tls
│       │           ├── ca.crt
│       │           ├── server.crt
│       │           └── server.key
│       ├── tlsca   保证传输数据的完整性和安全性
│       │   ├── 138f1cfd2708bca1e9e525773af410d46cef12736c3673ed787d7bbc38f013a4_sk
│       │   └── tlsca.example.com-cert.pem
│       └── users
│           └── Admin@example.com      admin管理员
│               ├── msp
│               │   ├── admincerts
│               │   ├── cacerts
│               │   ├── keystore
│               │   ├── signcerts
│               │   └── tlscacerts
│               └── tls
│                   ├── ca.crt
│                   ├── client.crt
│                   └── client.key
└── peerOrganizations
├── org1.example.com            # 第一个组织的相关材料，每个组织会生成单独的根证书
│   ├── ca  #存放组织的根证书和对应的私钥文件，默认采用EC 算法，证书为自签名。组织内的实体将基于该根证书作为证书根。
│   │   ├── 9b78dd1cc0570c9ef3f3fa31a1b343e7a6c0f157a2cc17f75412e12f2936898c_sk
│   │   └── ca.org1.example.com-cert.pem
│   ├── msp                 # 存放代表该组织的身份信息
│   │   ├── admincerts          # 组织管理员的身份验证证书，被根证书签名
│   │   │   └── Admin@org1.example.com-cert.pem
│   │   ├── cacerts             # 组织的根证书，同ca 目录下文件
│   │   │   └── ca.org1.example.com-cert.pem
│   │   ├── config.yaml
│   │   └── tlscacerts          # ：用于TLS 的CA 证书，自签名
│   │       └── tlsca.org1.example.com-cert.pem
│   ├── peers           # 存放属于该组织的所有Peer 节点
│   │   ├── peer0.org1.example.com    # 第一个peer 的信息，包括其msp 证书和tls 证书两类
│   │   │   ├── msp     
│   │   │   │   ├── admincerts              # 组织管理员的身份验证证书。Peer 将基于这些证书来认证交易签署者是否为管理员身份     
│   │   │   │   ├── cacerts             # 存放组织的根证书
│   │   │   │   ├── config.yaml         
│   │   │   │   ├── keystore                # 本节点的身份私钥，用来签名
│   │   │   │   ├── signcerts               # 验证本节点签名的证书，被组织根证书签名
│   │   │   │   └── tlscacerts              # TLS 连接用的身份证书，即组织TLS 证书
│   │   │   └── tls     # 存放tls 相关的证书和私钥
│   │   │       ├── ca.crt          # 组织的根证书
│   │   │       ├── server.crt      # 验证本节点签名的证书，被组织根证书签名
│   │   │       └── server.key      # 本节点的身份私钥，用来签名
│   │   └── peer1.org1.example.com      # 第二个peer 的信息，与peer0.org1.example.com结构类似
│   │       ├── msp
│   │       │   ├── admincerts
│   │       │   ├── cacerts
│   │       │   ├── config.yaml
│   │       │   ├── keystore
│   │       │   ├── signcerts
│   │       │   └── tlscacerts
│   │       └── tls
│   │           ├── ca.crt
│   │           ├── server.crt
│   │           └── server.key
│   ├── tlsca
│   │   ├── cf4587814bc05f9f81ac3d990c365660dedf1479e60f737c7e9e707727a27168_sk
│   │   └── tlsca.org1.example.com-cert.pem
│   └── users       # 存放属于该组织的用户的实体
│       ├── Admin@org1.example.com      # 管理员用户的信息，包括其msp 证书和tls 证书两类
│       │   ├── msp
│       │   │   ├── admincerts          # 管理身份验证证书
│       │   │   ├── cacerts             # 存放组织的根证书
│       │   │   ├── keystore            # 本用户的身份私钥，用来签名
│       │   │   ├── signcerts           # 管理员用户的身份验证证书，被组织根证书签名。要被某个Peer认可，则必须放到该Peer 的msp/admincerts 下
│       │   │   └── tlscacerts          # TLS 连接用的身份证书，即组织TLS 证书
│       │   └── tls     # 存放tls 相关的证书和私钥
│       │       ├── ca.crt      # 组织的根证书
│       │       ├── client.crt      # 管理员的用户身份验证证书，被组织根证书签名
│       │       └── client.key  # 管理员用户的身份私钥，用来签名
│       └── User1@org1.example.com      # 第一个用户的信息，包括msp 证书和tls 证书两类
│           ├── msp
│           │   ├── admincerts      # 管理身份验证证书
│           │   ├── cacerts         # 存放组织的根证书
│           │   ├── keystore            # 本用户的身份私钥，用来签名
│           │   ├── signcerts       # 验证本用户签名的身份证书，被组织根证书签名
│           │   └── tlscacerts      # TLS 连接用的身份证书，即组织TLS 证书
│           └── tls         # 存放tls 相关的证书和私钥
│               ├── ca.crt      # 组织的根证书
│               ├── client.crt      # 验证用户签名的身份证书，被组织根证书签名
│               └── client.key      # 用户的身份私钥，用来签名
└── org2.example.com                # 第二个组织的信息，与org1.example.com结构类似
    ├── ca
    │   ├── 91fd76daf883a57066303fb6842ff4fb07c6793dbc8fbbca6303efea455884b2_sk
    │   └── ca.org2.example.com-cert.pem
    ├── msp
    │   ├── admincerts
    │   │   └── Admin@org2.example.com-cert.pem
    │   ├── cacerts
    │   │   └── ca.org2.example.com-cert.pem
    │   ├── config.yaml
    │   └── tlscacerts
    │       └── tlsca.org2.example.com-cert.pem
    ├── peers
    │   ├── peer0.org2.example.com
    │   │   ├── msp
    │   │   │   ├── admincerts
    │   │   │   ├── cacerts
    │   │   │   ├── config.yaml
    │   │   │   ├── keystore
    │   │   │   ├── signcerts
    │   │   │   └── tlscacerts
    │   │   └── tls
    │   │       ├── ca.crt
    │   │       ├── server.crt
    │   │       └── server.key
    │   └── peer1.org2.example.com
    │       ├── msp
    │       │   ├── admincerts
    │       │   ├── cacerts
    │       │   ├── config.yaml
    │       │   ├── keystore
    │       │   ├── signcerts
    │       │   └── tlscacerts
    │       └── tls
    │           ├── ca.crt
    │           ├── server.crt
    │           └── server.key
    ├── tlsca
    │   ├── d3c3e6e37d306992bc9fb826415ed77971031418db48c195d5a24521916f32f3_sk
    │   └── tlsca.org2.example.com-cert.pem
    └── users
        ├── Admin@org2.example.com
        │   ├── msp
        │   │   ├── admincerts
        │   │   ├── cacerts
        │   │   ├── keystore
        │   │   ├── signcerts
        │   │   └── tlscacerts
        │   └── tls
        │       ├── ca.crt
        │       ├── client.crt
        │       └── client.key
        └── User1@org2.example.com
            ├── msp
            │   ├── admincerts
            │   ├── cacerts
            │   ├── keystore
            │   ├── signcerts
            │   └── tlscacerts
            └── tls
                ├── ca.crt
                ├── client.crt
                └── client.key
</code></pre><p>Cryptogen 按照配置文件中指定的结构生成了对应的组织和密钥、证书文件</p>
<p>其中最关键的是各个资源下的msp 目录内容，存储了生成的代表MSP 身份的各种证书文件，一般包括：</p>
<ul>
<li>admincerts ：管理员的身份证书文件</li>
<li>cacerts ：信任的根证书文件</li>
<li>key store ：节点的签名私钥文件</li>
<li>signcerts ：节点的签名身份证书文件</li>
<li>tlscacerts: TLS 连接用的证书</li>
<li>intermediatecerts （可选）：信任的中间证书</li>
<li>crls （可选）：证书撤销列表</li>
<li>config.yaml （可选）：记录OrganizationalUnitldentifiers 信息，包括根证书位置和ID信息</li>
</ul>
<p>之后配置环境变量，告诉configtxgen工具在哪里寻找configtx.yaml 文件</p>
<pre><code>$ export FABRIC_CFG_PATH=$PWD
</code></pre><h2 id="1-2-创建Orderer的初始区块并启动Orderer服务"><a href="#1-2-创建Orderer的初始区块并启动Orderer服务" class="headerlink" title="1.2.创建Orderer的初始区块并启动Orderer服务"></a>1.2.创建Orderer的初始区块并启动Orderer服务</h2><p>指定使用  configtx.yaml 文件中定义的  TwoOrgsOrdererGenesis 模板, 生成Ordering服务系统通道的初始区块文件。</p>
<pre><code>$ sudo ../bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
</code></pre><p>模版内容configtx.yaml:</p>
<pre><code># configtx.yaml
Profiles:

TwoOrgsOrdererGenesis:生成orderer初始区块的配置
    Capabilities:
        &lt;&lt;: *ChannelCapabilities
    Orderer:
        &lt;&lt;: *OrdererDefaults
        Organizations:
            - *OrdererOrg 指定orderer的组织名称
        Capabilities:
            &lt;&lt;: *OrdererCapabilities
    Consortiums:指定联盟成员
        SampleConsortium:                Organizations:
                - *Org1
                - *Org2
TwoOrgsChannel:指定通道配置
    Consortium: SampleConsortium
    Application:
        &lt;&lt;: *ApplicationDefaults
        Organizations:指定当前通道加入的组织
            - *Org1
            - *Org2
        Capabilities:
            &lt;&lt;: *ApplicationCapabilities


Organizations:
- &amp;OrdererOrg
    Name: OrdererOrg
    ID: OrdererMSP指定orderer的MSP本地路径
    MSPDir: crypto-config/ordererOrganizations/example.com/msp
- &amp;Org1
    Name: Org1MSP
    ID: Org1MSP
    MSPDir: crypto-config/peerOrganizations/org1.example.com/msp
    AnchorPeers:指定锚节点，固定的指定
         - Host: peer0.org1.example.com
          Port: 7051
- &amp;Org2
    Name: Org2MSP
    ID: Org2MSP
    MSPDir: crypto-config/peerOrganizations/org2.example.com/msp
    AnchorPeers:
        - Host: peer0.org2.example.com
          Port: 7051

Orderer: &amp;OrdererDefaults
OrdererType: solo或者Kafka
Addresses:
    - orderer.example.com:7050
BatchTimeout: 2s处理一批消息的超时时间
BatchSize:指定区块大小
    MaxMessageCount: 10指定最大的处理消息个数
    AbsoluteMaxBytes: 99 MB不管在什么情况下，区块的最大的大小不能超出这个大小
    PreferredMaxBytes: 512 KB建议区块大小，在单个消息不超过指定值的时候，如果超过了512k指定的值（不能超过指定的最大值，即上面的99M大小），也可以生成区块
Kafka:
    Brokers:
        - 127.0.0.1:9092 kafaka地址端口号
   Organizations:
Application: &amp;ApplicationDefaults
Organizations:

Capabilities:
Global: &amp;ChannelCapabilities
    V1_1: true
Orderer: &amp;OrdererCapabilities
    V1_1: true
Application: &amp;ApplicationCapabilities
    V1_1: true
</code></pre><h2 id="1-3-生成应用通道配置交易文件"><a href="#1-3-生成应用通道配置交易文件" class="headerlink" title="1.3.生成应用通道配置交易文件"></a>1.3.生成应用通道配置交易文件</h2><p>生成应用通道配置交易文件时，务必要替换$CHANNEL_NAME或设置CHANNEL_NAME为可在整个说明中使用的环境变量。</p>
<pre><code>$ export CHANNEL_NAME=mychannel
</code></pre><p>之后指定使用 configtx.yaml 配置文件中的 TwoOrgsChannel 模板, 来生成新建通道的配置交易文件, TwoOrgsChannel 模板指定了Org1和Org2都属于后面新建的应用通道。</p>
<pre><code>$ sudo ../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
</code></pre><h2 id="1-4-生成锚节点更新配置文件"><a href="#1-4-生成锚节点更新配置文件" class="headerlink" title="1.4.生成锚节点更新配置文件"></a>1.4.生成锚节点更新配置文件</h2><p>节点配置更新文件用来对组织的锚节点进行配置，这个同样基于  configtx.yaml 配置文件生成新建通道文件, 每个组织都需要分别生成且注意指定对应的组织名称。</p>
<pre><code>$ sudo ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
$ sudo ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
</code></pre><h1 id="2-启动网络"><a href="#2-启动网络" class="headerlink" title="2.启动网络"></a>2.启动网络</h1><h2 id="2-1-启动Docker容器"><a href="#2-1-启动Docker容器" class="headerlink" title="2.1.启动Docker容器"></a>2.1.启动Docker容器</h2><p>启动docker容器之前，先启动一系列服务，orderer，peers节点，<br>要启动多个容器，使用docker-compose来一条命令全部启动，在配置文件中，配置信息。</p>
<pre><code>$ sudo docker-compose -f docker-compose-cli.yaml up -d
</code></pre><p>-f: 指定docker-compose文件（指定启动网络时所使用的配置文件），该配置文件中描述了启动网络对应该有哪些容器被启动，同时指定容器中所挂载的内容</p>
<p>-d： 在启动过程中不显示详细的启动内容</p>
<p>网络启动顺序: 首先启动Orderer节点, 然后启动Peer节点,Peer节点启动后, 默认情况下没有加入网络中的任何应用通道, 也不会与Orderer服务建立连接.需要通过客户端对其进行操作, 让它加入网络和指定的应用通道中。</p>
<p>docker-compose-cli.yaml文件内容：<br>    version: ‘2’</p>
<pre><code>volumes:
  orderer.example.com:
  peer0.org1.example.com:
  peer1.org1.example.com:
  peer0.org2.example.com:
  peer1.org2.example.com:

networks:
  byfn:

services:服务

orderer.example.com:
extends:继承
  file:   base/docker-compose-base.yaml
  service: orderer.example.com
container_name: 容器名称orderer.example.com
networks:
  - byfn

peer0.org1.example.com:
container_name: peer0.org1.example.com
extends:
  file:  base/docker-compose-base.yaml
  service: peer0.org1.example.com
networks:
  - byfn

peer1.org1.example.com:
container_name: peer1.org1.example.com
extends:
  file:  base/docker-compose-base.yaml
  service: peer1.org1.example.com
networks:
  - byfn

peer0.org2.example.com:
container_name: peer0.org2.example.com
extends:
  file:  base/docker-compose-base.yaml
  service: peer0.org2.example.com
networks:
  - byfn

peer1.org2.example.com:
container_name: peer1.org2.example.com
extends:
  file:  base/docker-compose-base.yaml
  service: peer1.org2.example.com
networks:
  - byfn

cli:
container_name: cli
image: hyperledger/fabric-tools:$IMAGE_TAG
tty: true
stdin_open: true
environment:
  - GOPATH=/opt/gopath
  - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
  #- CORE_LOGGING_LEVEL=DEBUG
  - CORE_LOGGING_LEVEL=INFO
  - CORE_PEER_ID=cli
  - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
  - CORE_PEER_LOCALMSPID=Org1MSP
  - CORE_PEER_TLS_ENABLED=true
  - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
  - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
  - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
  - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
    - /var/run/:/host/var/run/
    - ./../chaincode/:/opt/gopath/src/github.com/chaincode
    - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
    - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
    - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
  - orderer.example.com
  - peer0.org1.example.com
  - peer1.org1.example.com
  - peer0.org2.example.com
  - peer1.org2.example.com
networks:
  - byfn
</code></pre><h2 id="2-2-进入容器中"><a href="#2-2-进入容器中" class="headerlink" title="2.2.进入容器中"></a>2.2.进入容器中</h2><p>执行如下命令进入到CLI容器中(后继操作都在容器中执行).</p>
<pre><code>$ sudo docker exec -it cli bash
</code></pre><p>如果成功, 命令提示符会变为如下内容:</p>
<pre><code>root@b240e1643244:/opt/gopath/src/github.com/hyperledger/fabric/peer#
</code></pre><p>接下来，真正在fabric网络环境中创建真正的通道，之前只是创建配置文件，指定访问成员策略的。</p>
<h2 id="2-3-创建应用通道"><a href="#2-3-创建应用通道" class="headerlink" title="2.3.创建应用通道"></a>2.3.创建应用通道</h2><p>检查环境变量是否正确设置：</p>
<pre><code>$ echo $CHANNEL_NAME
</code></pre><p>设置环境变量：</p>
<pre><code>$ export CHANNEL_NAME=mychannel
</code></pre><p>创建通道：</p>
<pre><code>$ peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
</code></pre><p>-o: orderer服务的地址（每一个通道首先都要链接orderer 服务）（因为在配置文件中指定过peer节点的配置，所以无需再次指定）</p>
<p>-c：指定创建通道的名称</p>
<p>-f:指定通道的配置交易文件所在路径</p>
<p>–tls:指定是否开启tls验证，保证收据的完整性，安全性</p>
<p>–cafile：指定mspd的ca证书。orderer组织里面的ca证书所属路径，属于msp成员管理服务里面的</p>
<h2 id="2-4-将对应节点加入到应用通道"><a href="#2-4-将对应节点加入到应用通道" class="headerlink" title="2.4.将对应节点加入到应用通道"></a>2.4.将对应节点加入到应用通道</h2><p>应用通道所包含组织的成员节点可以加入通道中：</p>
<pre><code>peer channel join -b mychannel.block
</code></pre><p>join命令: 将本Peer节点加入到某个应用通道中</p>
<p>-b: 初始区块文件的路径信息</p>
<h2 id="2-5-更新锚节点"><a href="#2-5-更新锚节点" class="headerlink" title="2.5.更新锚节点"></a>2.5.更新锚节点</h2><p>使用Org1的管理员身份更新锚节点配置</p>
<pre><code>$ peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
</code></pre><p>使用Org2的管理员身份更新锚节点配置</p>
<pre><code>$ CORE_PEER_LOCALMSPID=&quot;Org2MSP&quot;
$ CORE_PEER_ADDRESS=peer0.org2.example.com:7051`
$ CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
$ CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 

$ peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
</code></pre><p>这样的话，手动启动first-network网络的流程就完全结束。</p>
<h1 id="3-测试自己编写的链码"><a href="#3-测试自己编写的链码" class="headerlink" title="3.测试自己编写的链码"></a>3.测试自己编写的链码</h1><p>按照上述步骤手动启动first-network网络后，将放在GOPATH目录下的代码拷贝到cli容器中。</p>
<pre><code>docker cp ./myChaincode.go cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/
</code></pre><p>然后安装链码：</p>
<pre><code>peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/peer/
</code></pre><p>之后实例化链码：</p>
<pre><code>peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc -v 1.0 -c &apos;{&quot;Args&quot;:[&quot;init&quot;,&quot;3&quot;,&quot;A&quot;,&quot;B&quot;,&quot;C&quot;]}&apos; -P &quot;OR (&apos;Org1MSP.peer&apos;, &apos;Org2MSP.peer&apos;)&quot;
</code></pre><p>然后出现了如下错误：</p>
<pre><code>Error: could not assemble transaction, err Proposal response was not successful, error code 500, msg failed to execute transaction
error starting container: error starting container: Failed to generate platform-specific docker build: Error returned from build: 2
</code></pre><p>错误：无法组装事务，错误建议响应不成功，错误代码500，MSG未能执行事务。<br>错误启动容器：未能生成特定于平台的坞构建：从Bug返回的错误：2</p>
<p>对于这个错误，我暂时还没有头绪怎么解决。下面附上自己编写的关于投票链码的代码。</p>
<pre><code>package main
import (
    &quot;fmt&quot;
    &quot;strconv&quot;
    &quot;github.com/hyperledger/fabric/core/chaincode/shim&quot;
    &quot;github.com/hyperledger/fabric/protos/peer&quot;
)
type MySimpleChaincode struct {
    // 用于shim.start时，作为new的对象；
    // 包含类的各种方法，比如Init、Invoke、set、get
}
func (t *MySimpleChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
    fmt.Println(&quot;MySimpleChaincode -&gt; Init&quot;)
    _, args := stub.GetFunctionAndParameters()
    count,err = Atoi(args[0])
    if err != nil{
        shim.Error(err.Error())
    }
    candidate := make([]string, count)
    if len(args) != (count + 1) {
        return shim.Error(&quot;参数数量不对&quot;)
    }
    for i := 0; i &lt; args[0]; i++ {
        err := stub.PutState(candidate[i], []byte(0))
        if err != nil{
            shim.Error(err.Error())
        }
    }

    return shim.Success(nil)
}
func (t *MySimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
    fmt.Println(&quot;MySimpleChaincode -&gt; Invoke&quot;)
    function, args := stub.GetFunctionAndParameters()
    if function == &quot;vote&quot; {
        return t.vote(stub, args)
    }else if function == &quot;addCandidates&quot; {
        return t.addSome(stub, args)
    }else if function == &quot;deleteCandidates&quot; {
        return t.deleteOne(stub, args)
    }else if function == &quot;queryCAndidates&quot; {
        return t.querySome(stub, args)
    }else if function == &quot;queryAllCandidates&quot; {
        return t.queryAll(stub, args)
    }
    return shim.Error(&quot;方法名错误&quot;)
}
func (t *MySimpleChaincode) vote(stub shim.ChaincodeStubInterface, args []string) peer.Response {
    if len(args) == 0 {
        return shim.Error(&quot;参数数量不能为空&quot;)
    }
    for i := 0; i &lt; count; i++ {
        if args[0] == candidate[i] {
            n,err = stub.GetState(candidate[i])
            if err!= nil{
                return shim.Error(err.Error())
            }
            err := stub.PutState(candidate[i],[]byte(n + 1))
            if err!= nil{
                return shim.Error(err.Error())
            }
        }
    }
    return shim.Success(nil)
}
func (t *MySimpleChaincode) addCandidates(stub shim.ChaincodeStubInterface, args []string) peer.Response {
    if len(args) == 0 {
        return shim.Error(&quot;参数数量不能为空&quot;)
    }
    n = len(args)
    for i := 0; i &lt; n; i++ {
        newcandidate = append(candidate, args[i])
        candidate = newcandidate

        err := stub.PutState(args[i],[]byte(0))
        if err != 0 {
            return shim.Error(err.Error())
        }
    }
    return shim.Success(nil)
}
func (t *MySimpleChaincode) deleteCandidates(stub shim.ChaincodeStubInterface, args []string) peer.Response {
    if len(args) == 0 {
        return shim.Error(&quot;参数数量不能为空&quot;)
    }
    n = len(args)
    for i := 0; i &lt; n; i++ {
        err := stub.DelState(args[i])
        if err != 0 {
            return shim.Error(&quot;参数中有非候选人&quot;)
        }
    }
    return shim.Success(nil)
}
func (t *MySimpleChaincode) queryCandidates(stub shim.ChaincodeStubInterface, args []string) peer.Response {
    if len(args) == 0 {
        return shim.Error(&quot;参数数量不能为空&quot;)
    }
    n = len(args)
    temp := make([]string, len(args))
    for i := 0; i &lt; n; i++ {
        temp[i], err := stub.GetState(args[i])
        if err != nil {
            return shim.Error(&quot;参数中有非候选人&quot;)
        }
    }
    return shim.Success(temp)
}
func (t *MySimpleChaincode) queryAllCandidates(stub shim.ChaincodeStubInterface, args []string) peer.Response {
    if len(args) ！= 0 {
        return shim.Error(&quot;参数数量不对&quot;)
    }
    n = len(candidate)
    temp := make([]string, len(args))
    for i := 0; i &lt; n; i++ {
        temp[i], err := stub.GetState(args[i])
        if err != nil {
            return shim.Error(err.Error())
        }
    }
    return shim.Success(temp)
}
func main() {
    err := shim.Start(new(MySimpleChaincode))
    if err != nil {
        fmt.Printf(&quot;链码部署失败: %s&quot;, err)
    }
}
</code></pre>  
	</div>
		<footer class="article-footer clearfix">
<div class="article-catetags">


  <div class="article-tags">
  
  <span></span> <a href="/tags/周报/">周报</a><a href="/tags/卢家豪/">卢家豪</a>
  </div>

</div>



	<div class="article-share" id="share">
	
	  <div data-url="http://b3434lockchain.gitee.io/2018/11/05/lujiahao/lujiahao4/" data-title="周报 | B3434lockchain" data-tsina="" class="share clearfix">
	  </div>
	
	</div>


</footer>

   	       
	</article>
	
<nav class="article-nav clearfix">
 
 <div class="prev" >
 <a href="/2018/11/05/susijie/susijie4/" title="第五周周报">
  <strong>上一篇：</strong><br/>
  <span>
  第五周周报</span>
</a>
</div>


<div class="next">
<a href="/2018/11/05/tanjunxi/tanjunxi4/"  title="谭俊熙_Fabric-sdk-java调试">
 <strong>下一篇：</strong><br/> 
 <span>谭俊熙_Fabric-sdk-java调试
</span>
</a>
</div>

</nav>

	



</div>  
      <div class="openaside"><a class="navbutton" href="#" title="Show Sidebar"></a></div>

  <div id="toc" class="toc-aside">
  <strong class="toc-title">Contents</strong>
 
 <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1-手动启动first-network的准备工作"><span class="toc-number">1.</span> <span class="toc-text">1.手动启动first-network的准备工作</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-1-生成组织结构及身份证书"><span class="toc-number">1.1.</span> <span class="toc-text">1.1.生成组织结构及身份证书</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-2-创建Orderer的初始区块并启动Orderer服务"><span class="toc-number">1.2.</span> <span class="toc-text">1.2.创建Orderer的初始区块并启动Orderer服务</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-3-生成应用通道配置交易文件"><span class="toc-number">1.3.</span> <span class="toc-text">1.3.生成应用通道配置交易文件</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-4-生成锚节点更新配置文件"><span class="toc-number">1.4.</span> <span class="toc-text">1.4.生成锚节点更新配置文件</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2-启动网络"><span class="toc-number">2.</span> <span class="toc-text">2.启动网络</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#2-1-启动Docker容器"><span class="toc-number">2.1.</span> <span class="toc-text">2.1.启动Docker容器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-2-进入容器中"><span class="toc-number">2.2.</span> <span class="toc-text">2.2.进入容器中</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-3-创建应用通道"><span class="toc-number">2.3.</span> <span class="toc-text">2.3.创建应用通道</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-4-将对应节点加入到应用通道"><span class="toc-number">2.4.</span> <span class="toc-text">2.4.将对应节点加入到应用通道</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-5-更新锚节点"><span class="toc-number">2.5.</span> <span class="toc-text">2.5.更新锚节点</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-测试自己编写的链码"><span class="toc-number">3.</span> <span class="toc-text">3.测试自己编写的链码</span></a></li></ol>
 
  </div>

<div id="asidepart">
<div class="closeaside"><a class="closebutton" href="#" title="Hide Sidebar"></a></div>
<aside class="clearfix">

  

  
<div class="tagslist">
	<p class="asidetitle">Tags</p>
		<ul class="clearfix">
		
			
				<li><a href="/tags/周报/" title="周报">周报<sup>23</sup></a></li>
			
		
			
				<li><a href="/tags/谭俊熙/" title="谭俊熙">谭俊熙<sup>11</sup></a></li>
			
		
			
				<li><a href="/tags/苏思捷/" title="苏思捷">苏思捷<sup>5</sup></a></li>
			
		
			
				<li><a href="/tags/学习报告/" title="学习报告">学习报告<sup>5</sup></a></li>
			
		
			
				<li><a href="/tags/卢家豪/" title="卢家豪">卢家豪<sup>5</sup></a></li>
			
		
			
				<li><a href="/tags/报告/" title="报告">报告<sup>5</sup></a></li>
			
		
			
				<li><a href="/tags/苏佳鑫/" title="苏佳鑫">苏佳鑫<sup>4</sup></a></li>
			
		
			
				<li><a href="/tags/冯华文/" title="冯华文">冯华文<sup>4</sup></a></li>
			
		
			
				<li><a href="/tags/周报反馈/" title="周报反馈">周报反馈<sup>2</sup></a></li>
			
		
			
				<li><a href="/tags/吴朝捷/" title="吴朝捷">吴朝捷<sup>2</sup></a></li>
			
		
			
				<li><a href="/tags/黎宁/" title="黎宁">黎宁<sup>1</sup></a></li>
			
		
			
				<li><a href="/tags/笔记/" title="笔记">笔记<sup>1</sup></a></li>
			
		
		</ul>
</div>


</aside>
</div>
    </div>
    <footer><div id="footer" >
	
	
	<div class="social-font" class="clearfix">
		
		
		
		
		
		
		
		
		
		
	</div>
			
		

		<p class="copyright">
		
		</p>
</div>
</footer>
    <script src="/js/jquery-2.0.3.min.js"></script>
<script src="/js/jquery.imagesloaded.min.js"></script>
<script src="/js/gallery.js"></script>
<script src="/js/jquery.qrcode-0.12.0.min.js"></script>

<script type="text/javascript">
$(document).ready(function(){ 
  $('.navbar').click(function(){
    $('header nav').toggleClass('shownav');
  });
  var myWidth = 0;
  function getSize(){
    if( typeof( window.innerWidth ) == 'number' ) {
      myWidth = window.innerWidth;
    } else if( document.documentElement && document.documentElement.clientWidth) {
      myWidth = document.documentElement.clientWidth;
    };
  };
  var m = $('#main'),
      a = $('#asidepart'),
      c = $('.closeaside'),
      o = $('.openaside');
  c.click(function(){
    a.addClass('fadeOut').css('display', 'none');
    o.css('display', 'block').addClass('fadeIn');
    m.addClass('moveMain');
  });
  o.click(function(){
    o.css('display', 'none').removeClass('beforeFadeIn');
    a.css('display', 'block').removeClass('fadeOut').addClass('fadeIn');      
    m.removeClass('moveMain');
  });
  $(window).scroll(function(){
    o.css("top",Math.max(80,260-$(this).scrollTop()));
  });
  
  $(window).resize(function(){
    getSize(); 
    if (myWidth >= 1024) {
      $('header nav').removeClass('shownav');
    }else{
      m.removeClass('moveMain');
      a.css('display', 'block').removeClass('fadeOut');
      o.css('display', 'none');
      
      $('#toc.toc-aside').css('display', 'none');
        
    }
  });
});
</script>

<script type="text/javascript">
$(document).ready(function(){ 
  var ai = $('.article-content>iframe'),
      ae = $('.article-content>embed'),
      t  = $('#toc'),
      ta = $('#toc.toc-aside'),
      o  = $('.openaside'),
      c  = $('.closeaside');
  if(ai.length>0){
    ai.wrap('<div class="video-container" />');
  };
  if(ae.length>0){
   ae.wrap('<div class="video-container" />');
  };
  c.click(function(){
    ta.css('display', 'block').addClass('fadeIn');
  });
  o.click(function(){
    ta.css('display', 'none');
  });
  $(window).scroll(function(){
    ta.css("top",Math.max(140,320-$(this).scrollTop()));
  });
});
</script>


<script type="text/javascript">
$(document).ready(function(){ 
  var $this = $('.share'),
      url = $this.attr('data-url'),
      encodedUrl = encodeURIComponent(url),
      title = $this.attr('data-title'),
      tsina = $this.attr('data-tsina'),
      description = $this.attr('description');
  var html = [
  '<div class="hoverqrcode clearfix"></div>',
  '<a class="overlay" id="qrcode"></a>',
  '<a href="https://www.facebook.com/sharer.php?u=' + encodedUrl + '" class="article-share-facebook" target="_blank" title="Facebook"></a>',
  '<a href="https://twitter.com/intent/tweet?url=' + encodedUrl + '" class="article-share-twitter" target="_blank" title="Twitter"></a>',
  '<a href="#qrcode" class="article-share-qrcode" title="微信"></a>',
  '<a href="http://widget.renren.com/dialog/share?resourceUrl=' + encodedUrl + '&srcUrl=' + encodedUrl + '&title=' + title +'" class="article-share-renren" target="_blank" title="人人"></a>',
  '<a href="http://service.weibo.com/share/share.php?title='+title+'&url='+encodedUrl +'&ralateUid='+ tsina +'&searchPic=true&style=number' +'" class="article-share-weibo" target="_blank" title="微博"></a>',
  '<span title="Share to"></span>'
  ].join('');
  $this.append(html);

  $('.hoverqrcode').hide();

  var myWidth = 0;
  function updatehoverqrcode(){
    if( typeof( window.innerWidth ) == 'number' ) {
      myWidth = window.innerWidth;
    } else if( document.documentElement && document.documentElement.clientWidth) {
      myWidth = document.documentElement.clientWidth;
    };
    var qrsize = myWidth > 1024 ? 200:100;
    var options = {render: 'image', size: qrsize, fill: '#2ca6cb', text: url, radius: 0.5, quiet: 1};
    var p = $('.article-share-qrcode').position();
    $('.hoverqrcode').empty().css('width', qrsize).css('height', qrsize)
                          .css('left', p.left-qrsize/2+20).css('top', p.top-qrsize-10)
                          .qrcode(options);
  };
  $(window).resize(function(){
    $('.hoverqrcode').hide();
  });
  $('.article-share-qrcode').click(function(){
    updatehoverqrcode();
    $('.hoverqrcode').toggle();
  });
  $('.article-share-qrcode').hover(function(){}, function(){
      $('.hoverqrcode').hide();
  });
});   
</script>











<link rel="stylesheet" href="/fancybox/jquery.fancybox.css" media="screen" type="text/css">
<script src="/fancybox/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
$(document).ready(function(){ 
  $('.article-content').each(function(i){
    $(this).find('img').each(function(){
      if ($(this).parent().hasClass('fancybox')) return;
      var alt = this.alt;
      if (alt) $(this).after('<span class="caption">' + alt + '</span>');
      $(this).wrap('<a href="' + this.src + '" title="' + alt + '" class="fancybox"></a>');
    });
    $(this).find('.fancybox').each(function(){
      $(this).attr('rel', 'article' + i);
    });
  });
  if($.fancybox){
    $('.fancybox').fancybox();
  }
}); 
</script>



<!-- Analytics Begin -->





<!-- Analytics End -->

<!-- Totop Begin -->

	<div id="totop">
	<a title="Back to Top"><img src="/img/scrollup.png"/></a>
	</div>
	<script src="/js/totop.js"></script>

<!-- Totop End -->

<!-- MathJax Begin -->
<!-- mathjax config similar to math.stackexchange -->


<!-- MathJax End -->

<!-- Tiny_search Begin -->

<!-- Tiny_search End -->

  </body>
</html>
